import os
import base64
import tkinter as tk
from tkinter import filedialog, messagebox
from functools import partial
import qrcode
from PIL import ImageTk, ImageDraw, ImageFont
import threading
import time
import math
import hashlib

stop_event = threading.Event()
pause_event = threading.Event()

_selectFileButton = None
_testButton = None
_startButton = None
_stopButton = None
_pauseButton = None
_toIndexButton = None
_filePathLabel = None
_maxPiecesLabel = None
_currentPiecesLabel = None

_toIndexValue = -1


def main():
    global _selectFileButton
    global _testButton
    global _startButton
    global _stopButton
    global _filePathLabel
    global _maxPiecesLabel
    global _currentPiecesLabel
    global _pauseButton
    global _toIndexButton
    window = genWindow()
    headFrame = tk.Frame(window, width=window.winfo_width(),
                         height=window.winfo_width())
    headFrame.grid(row=0)
    qrFrame = tk.Frame(window, width=window.winfo_width(),
                       height=window.winfo_width())
    qrFrame.grid(row=1)
    _canvas = canvas(qrFrame)
    _filePathLabel = filePathLabel(headFrame)
    _selectFileButton = selectFileButton(headFrame)
    _testButton = testButton(headFrame, _canvas)
    _maxPiecesLabel, _currentPiecesLabel = piecesLabel(headFrame)
    setMaxPieceLabelText(0)
    setCurrentPieceLabelText(0)
    _startButton = startButton(headFrame, _canvas)
    _stopButton = stopButton(headFrame, _canvas)
    _pauseButton = pauseButton(headFrame, _canvas)
    _toIndexButton = toIndex(headFrame)

    window.mainloop()


def buttonState(selectFileButtonState, testButtonState, startButtonState, stopButtonState, pauseButtonState):
    _selectFileButton["state"] = tk.NORMAL if selectFileButtonState else tk.DISABLED
    _testButton["state"] = tk.NORMAL if testButtonState else tk.DISABLED
    _startButton["state"] = tk.NORMAL if startButtonState else tk.DISABLED
    _stopButton["state"] = tk.NORMAL if stopButtonState else tk.DISABLED
    _pauseButton["state"] = tk.NORMAL if pauseButtonState else tk.DISABLED


def piecesLabel(parent):
    maxPiecesLabel = tk.Label(
        parent, text="",  borderwidth=1, relief="ridge", width=16)
    maxPiecesLabel.grid(row=0, column=8)
    currentPiecesLabel = tk.Label(
        parent, text="",  borderwidth=1, relief="ridge", width=16)
    currentPiecesLabel.grid(row=0, column=9)
    return maxPiecesLabel, currentPiecesLabel


def setMaxPieceLabelText(max=0):
    setLabelText(_maxPiecesLabel, "total: " + str(max))


def setCurrentPieceLabelText(max=0):
    setLabelText(_currentPiecesLabel, "current: " + str(max))


def setLabelText(label, text=""):
    label.config(text=text)


def toIndex(parent):
    toIndexValue = tk.StringVar()
    toIndexValue.set("")
    entry = tk.Entry(parent, width=11, textvariable=toIndexValue)
    entry.grid(row=0, column=6)
    button = tk.Button(parent, text="ToIndex", command=partial(
        toIndexButtonClick, toIndexValue))
    button.grid(row=0, column=7)
    return button


def toIndexButtonClick(toIndexValue):
    global _toIndexValue
    print("toIndex")
    toIndex = toIndexValue.get()
    if (not toIndex.isdigit()):
        print("not a digit")
        return
    _toIndexValue = int(toIndex)


def pauseButton(parent, canvas):
    button = tk.Button(parent, text="Pause", width=7,
                       state=tk.DISABLED, command=partial(pauseButtonClick, canvas))
    button.grid(row=0, column=5)
    return button


def pauseButtonClick(canvas):
    print("pause")
    if (pause_event.isSet()):
        pause_event.clear()
        _pauseButton.config(text="Pause")
    else:
        pause_event.set()
        _pauseButton.config(text="Continue")


def stopButton(parent, canvas):
    button = tk.Button(parent, text="Stop", state=tk.DISABLED,
                       command=partial(stopButtonClick, canvas))
    button.grid(row=0, column=4)
    return button


def stopButtonClick(canvas):
    print("stop")
    stop_event.set()


def startButton(parent, canvas):
    button = tk.Button(parent, text="Start",
                       command=partial(startButtonClick, canvas))
    button.grid(row=0, column=3)
    return button


def startButtonClick(canvas):
    print("start")
    stop_event.clear()
    pause_event.clear()
    filePath = _filePathLabel.cget("text")
    if not filePath:
        print("select a file")
        return
    if (os.path.getsize(filePath) > 10 * 1024 * 1024):
        print("file too large")
        return
    buttonState(False, False, False, True, True)
    thread = threading.Thread(target=startQr, args=(canvas, filePath))
    thread.setDaemon(True)
    thread.start()


def startQr(canvas, filePath):
    global _toIndexValue
    try:
        with open(filePath, "rb") as file:
            fileContent = file.read()
        fileName = os.path.basename(filePath)
        base64Content = base64.b64encode(fileContent).decode("utf-8")
        pieceLengh = 2000
        maxPieces = math.ceil(len(base64Content) / pieceLengh)
        setMaxPieceLabelText(maxPieces)
        md5 = hashlib.md5()
        md5.update(base64Content.encode("utf-8"))
        md5Hex = md5.hexdigest()
        img = getQr("start-" + md5Hex + "-" + fileName, "START")
        drawQr(canvas, img)
        time.sleep(5)
        interval = 0.3
        toIndexValue = -1
        base64ContentLen = len(base64Content)
        content = ""
        index = 0
        pieceIndex = 0
        setCurrentPieceLabelText(0)
        while (index < base64ContentLen):
            if pause_event.isSet():
                time.sleep(1)
                img = getQr("pause-pause", "PAUSE")
                drawQr(canvas, img)
                buttonState(False, False, False, True, True)
                continue
            char = base64Content[index]
            index = index + 1
            if stop_event.isSet():
                img = getQr("stop-stop", "STOP")
                drawQr(canvas, img)
                buttonState(True, True, True, False, False)
                _pauseButton.config(text="Pause")
                setMaxPieceLabelText(0)
                setCurrentPieceLabelText(0)
                return
            if (_toIndexValue != -1):
                toIndexValue = _toIndexValue
                content = ""
                index = 0
                pieceIndex = 0
                setCurrentPieceLabelText(0)
                _toIndexValue = -1
                continue
            content = content + char
            if (len(content) >= pieceLengh or (index == base64ContentLen and len(content) > 0)):
                pieceIndex = pieceIndex + 1
                setCurrentPieceLabelText(pieceIndex)
                if (toIndexValue != -1):
                    if (pieceIndex < toIndexValue):
                        content = ""
                        continue
                    toIndexValue = -1
                content = str(pieceIndex) + "-" + content
                img = getQr(content)
                drawQr(canvas, img)
                content = ""
                time.sleep(interval)
        time.sleep(1)
        img = getQr("end-end", "END")
        drawQr(canvas, img)
    finally:
        buttonState(True, True, True, False, False)


def testButton(parent, canvas):
    button = tk.Button(parent, text="Test",
                       command=partial(testButtonClick, canvas))
    button.grid(row=0, column=2)
    return button


def testButtonClick(canvas):
    print("test")
    img = getQr("人间，又污秽了", "TEST")
    drawQr(canvas, img)


def drawQr(canvas, img):
    canvas.create_image(0, 0, anchor=tk.NW, image=img)


def getQr(content, centerWord=""):
    global img_tk
    qr = qrcode.QRCode(
        version=21, error_correction=qrcode.constants.ERROR_CORRECT_M,  box_size=3, border=1)
    qr.add_data(content)
    img = qr.make_image(fill_color="black",
                        back_color="white").resize((444, 444))
    img = img.convert("RGB")
    width, height = img.size
    draw = ImageDraw.Draw(img)
    font = ImageFont.truetype("arial.ttf", 20)
    font.font_variant = "bold"
    left, top, right, bottom = draw.textbbox((0, 0), centerWord, font)
    x = (width - (right - left)) / 2
    y = (height - (bottom - top)) / 2
    draw.text((x, y), centerWord, fill="#FF0000", font=font)
    img_tk = ImageTk.PhotoImage(img)
    return img_tk


def canvas(parent):
    canvas = tk.Canvas(parent, width=555, height=555)
    canvas.grid(row=0, column=0, padx=11, pady=11)
    return canvas


def selectFileButton(parent):
    button = tk.Button(parent, text="Select file", command=partial(selectFile))
    button.grid(row=0, column=1)
    return button


def filePathLabel(parent):
    label = tk.Label(parent, text="", anchor="e",
                     borderwidth=1, relief="ridge", width=33)
    label.grid(row=0, column=0)
    return label


def selectFile():
    filePath = filedialog.askopenfilename(title="Select file")
    print(filePath)
    _filePathLabel.config(text=filePath)
    setMaxPieceLabelText(0)
    setCurrentPieceLabelText(0)


def genWindow():
    window = tk.Tk()
    window.title("-")
    window.geometry("854x500+111+111")
    window.iconphoto(False, tk.PhotoImage(file='icon.png'))
    window.resizable(False, False)
    window.attributes("-topmost", True)
    return window


if __name__ == "__main__":
    main()
